#ifndef _PROCESS_POOL_HPP_git
#define _PROCESS_POOL_HPP_

#include <vector>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include "Task.hpp"

// 设置进程池的进程数量
int gdefaulnum = 5;

// 先描述，一个进程信道
class Channel
{
public:
    Channel(int wfd, pid_t subid) : _wfd(wfd), _subid(subid)
    {
        _name = "channel" + '-' + std::to_string(wfd) + "-" + std::to_string(subid);
    }

    void Close()
    {
        close(_wfd);
    }

    void Wait()
    {
        pid_t id = waitpid(_wfd, nullptr, 0);
        // void(id);
    }

    // 发送消息给子进程
    void Send(int code)
    {
        int n = write(_wfd, &code, sizeof(code));
    }

    int Wfd() { return _wfd; }
    pid_t Subid() { return _subid; }
    std::string Name() { return _name; }

    ~Channel()
    {
    }

private:
    int _wfd;
    pid_t _subid;
    std::string _name;
};

// 再组织，对所有管道进行管理;
class ChannelManger
{
public:
    ChannelManger()
    {
    }
    // 打印进程池
    void PrintChannels()
    {
        for (auto &channel : _channels)
        {
            std::cout << channel.Name() << std::endl;
        }
    }

    Channel &Select()
    {
        //采用轮询的方式
        Channel &c = _channels[_next];
        _next++;
        _next %= _channels.size();
        return c;
        // return _channels[_next++];       这种没有拷贝的，如果被修改，可能直接影响到进程池本身。
    }
    // 关掉父进程写端
    void StopProcess()
    {
        for (auto &channel : _channels)
        {
            channel.Close();
        }
    }
    // 等待僵尸子进程
    void WaitProcess()
    {
        for (auto &channel : _channels)
        {
            channel.Wait();
        }
    }
    // 插入进程
    void Insert(int wfd, pid_t subid)
    {
        // channel c(wfd,subid);
        // _channles.push_back(std::move(c));
        _channels.emplace_back(wfd, subid);
    }

    ~ChannelManger()
    {
    }

private:
    int _next;
    std::vector<Channel> _channels;
};

// 构建进程池
// 父进程写，子进程读
class ProcessPool
{
public:
    ProcessPool(int process_num) : _process_num(process_num)
    {
        //注册任务
        _tm.Register(PrintLog);
        _tm.Register(Download);
        _tm.Register(Upload);
    }

    // Debug一下
    void Debug()
    {
        _cm.PrintChannels();
    }

    void Work(int rfd)
    {
        // 子进程从父进程里面读东西
        while (true)
        {
            sleep(2);
            int code = 0;
            ssize_t n = read(rfd, &code, sizeof(code));     //从父进程里读取一个任务码到code中
            if(n > 0)   //读取成功
            {
                if(n != sizeof(code))
                {
                    continue;
                }
                //根据收到的任务码执行任务
                std::cout << "子进程[" << getpid() << "]收到一个任务码: " << code << std::endl;
                _tm.Excute(code);
            }
            else if(n == 0)
            {
                std::cout << "子进程退出！" << std::endl;
                break;
            }
            else 
            {
                std::cout << "读取出错！"<< std::endl;
                break;
            }
        }
    }

    // 构建进程池
    bool Start()
    {
        while (_process_num--)
        {
            // 1.创建管道
            int fds[2] = {0};
            int n = pipe(fds);
            if (n < 0)
                return false;
            // 2.创建子进程
            pid_t subid = fork();
            if (subid < 0)
                return false;
            else if (subid == 0)
            {
                // child
                // 3.关闭写端
                close(fds[1]);
                // 子进程做工作
                Work(fds[0]);
                // 做完工作结束进程
                close(fds[0]);
                exit(1);
            }
            else
            {
                // father
                // 关闭读端
                close(fds[0]);
                // 将创建好的进程信道插入到进程池
                _cm.Insert(fds[1], subid);
            }
        }
        return true;
    }

    void Run()
    {
        //1. 选择一个信道
        Channel &c = _cm.Select();
        //2. 选择一个任务码
        int taskcode = _tm.Code();
        //3. 发送任务码
        c.Send(taskcode);
    }

    // 销毁进程池
    void Stop()
    {
        // 1.关掉读端
        _cm.StopProcess();
        // 2.等待僵尸子进程
        _cm.WaitProcess();
    }

    ~ProcessPool()
    {
    }

private:
    int _process_num;
    ChannelManger _cm;
    TaskManger _tm;
};

#endif